package classes {
	import flash.display.DisplayObjectContainer;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	
	import flashx.textLayout.formats.TextAlign;
	
	import interfaces.PaginationInterface;
	
	/**
	 * 
	 * @author dimetrix
	 * 
	 */	
	public class Pagination extends Object implements PaginationInterface {
		
		private static const LABEL_FIRST_TEXT:String = "начало";
		private static const LABEL_FIRST_SYMBOL:String = "<<<";
		private static const LABEL_PREV:String = "<";
		private static const LABEL_LAST_TEXT:String = "конец";
		private static const LABEL_LAST_SYMBOL:String = ">>>";
		private static const LABEL_NEXT:String = ">";

		/**
		 * Зациклить пагинацию
		 */		
		private static const CIRCLE:Boolean = false;
		
		private static const GAP:int = 10;
		
		// ---
		
		private var par:DisplayObjectContainer;
		private var x:Number;
		private var y:Number;
		private var totalPagesNo:uint;
		private var visiblePagesNo:uint;
		private var selectCallback:Function;
		private var autoSize:Boolean;
		
		private var w:Number;
		private var h:Number;
		
		private var newPageNo:int = 0;
		
		// ---
		
		private var container:Sprite;
		
		private var textFormat:TextFormat;
		private var textFormatOver:TextFormat;
		private var textFormatSelected:TextFormat;
		
		private var items:Array = [];
		
		/**
		 * 
		 * @param par
		 * @param x
		 * @param y
		 * @param totalPagesNo
		 * @param visiblePagesNo
		 * @param selectCallback
		 * @param autoSize
		 * 
		 */		
		public function Pagination(par:DisplayObjectContainer, x:Number, y:Number, totalPagesNo:uint, visiblePagesNo:uint, selectCallback:Function, autoSize:Boolean) {
			super();
			
			// ---
			
			this.par = par;
			this.x = x;
			this.y = y;
			this.totalPagesNo = totalPagesNo;
			this.visiblePagesNo = visiblePagesNo;
			this.selectCallback = selectCallback;
			this.autoSize = autoSize;
			
			// ---
			
			container = par.addChild(new Sprite()) as Sprite;
			
			textFormat = new TextFormat();
			textFormat.size = 18;
			textFormat.color = 0x999999;
			textFormat.underline = false;
			textFormat.align = TextAlign.CENTER;
			
			textFormatOver = new TextFormat();
			textFormatOver.size = 18;
			textFormatOver.color = 0x333333;
			textFormatOver.underline = false;
			textFormatOver.align = TextAlign.CENTER;
			 
			textFormatSelected = new TextFormat();
			textFormatSelected.size = 18;
			textFormatSelected.color = 0x000000;
			textFormatSelected.underline = true;
			textFormatSelected.align = TextAlign.CENTER;
			
			// ---
			
			showPage(newPageNo);
		}
		
		// --- PUBLIC
		
		/**
		 * 
		 * @param newPageNo
		 * @param skipCallback
		 * 
		 */		
		public function showPage(newPageNo:uint, skipCallback:Boolean = false):void {
			if(newPageNo >= 0 && newPageNo < totalPagesNo && this.newPageNo != newPageNo) {
				this.newPageNo = newPageNo; 
				
				buildInterface();
				
				if(!skipCallback && selectCallback != null) {
					selectCallback(newPageNo);
				}
			}
		}
		
		/**
		 * 
		 * @param w
		 * @param h
		 * 
		 */		
		public function setSize(w:Number, h:Number):void {
			this.width = w;
			this.height = h;
		}
		
		/**
		 * 
		 * @param w
		 * 
		 */		
		public function set width(w:Number):void {
			if(!autoSize) {
				this.w = w;
				
				buildLayout();
			}
		}
		
		/**
		 * 
		 * @param h
		 * 
		 */		
		public function set height(h:Number):void {
			this.h = h;
			
			buildLayout();
		}
		
		// --- PRIVATE
		
		private function buildInterface():void {
			while(container.numChildren) {
				container.removeChildAt(0);
			}	
			
			items = [];
			
			if(totalPagesNo > 0 && visiblePagesNo <= totalPagesNo) {
				
				var item:Item;
				
				item = new Item();
				item.action = Item.ACTION_FIRST;
				item.text = LABEL_FIRST_TEXT;
				item.textField = buildTextField(item, textFormat);
				item.enable = newPageNo != 0;
				items.push(item);
				
				item = new Item();
				item.action = Item.ACTION_FIRST;
				item.text = LABEL_FIRST_SYMBOL;
				item.textField = buildTextField(item, textFormat);
				item.enable = newPageNo != 0;
				items.push(item);
				
				item = new Item();
				item.action = Item.ACTION_PREV;
				item.text = LABEL_PREV;
				item.textField = buildTextField(item, textFormat);
				item.enable = CIRCLE ? true : newPageNo != 0;
				items.push(item);
				 
				var left:int = Math.max(newPageNo - visiblePagesNo / 2, 0);
				var right:int = Math.min(left + Math.min(visiblePagesNo, totalPagesNo), totalPagesNo);
					
				left = right - left < visiblePagesNo ? left - (visiblePagesNo - (right - left)) : left;
				
				for(var i:int = left; i < right; i++) {
					item = new Item();
					item.action = Item.ACTION_PAGINATION;
					item.index = i;
					item.text = String(i + 1);
					item.selectable = true;
					item.selected = (newPageNo == item.index);
					item.textField = buildTextField(item, textFormat);
					item.textField.defaultTextFormat = item.selected ? textFormatSelected : textFormat;
					item.textField.setTextFormat(item.selected ? textFormatSelected : textFormat);
					
					items.push(item);
				}
				
				item = new Item();
				item.action = Item.ACTION_NEXT;
				item.text = LABEL_NEXT;
				item.textField = buildTextField(item, textFormat);
				item.enable = CIRCLE ? true : newPageNo != totalPagesNo - 1;
				items.push(item);
				
				item = new Item();
				item.action = Item.ACTION_LAST;
				item.text = LABEL_LAST_SYMBOL;
				item.textField = buildTextField(item, textFormat);
				item.enable = newPageNo != totalPagesNo - 1;
				items.push(item);
				
				item = new Item();
				item.action = Item.ACTION_LAST;
				item.text = LABEL_LAST_TEXT;
				item.textField = buildTextField(item, textFormat);
				item.enable = newPageNo != totalPagesNo - 1;
				items.push(item);
				
				for each(item in items) {
					container.addChild(buildTextFieldContainer(item, labelMouseClick_Callback, labelMouseOver_Callback, labelMouseOut_Callback));
				}
			}
			
			buildLayout();
		}
		
		private function buildLayout():void {
			var item:Item;
			
			var xPos:Number = 0;
			var yPos:Number = 0;
			
			for each(item in items) {  
				if(autoSize) {
					item.textField.x = xPos;
				}
				
				item.textField.y = (h - item.textField.height) / 2;
				
				xPos += item.textField.width + GAP;
			}
			
			if(!autoSize) {
				var step:Number = (w - xPos) / (items.length - 1);
				
				xPos = 0;
				
				for each(item in items) {  
					item.textField.x = xPos;
					
					xPos += item.textField.width + step;
				}
			}
		}
		
		private function buildTextField(item:Item, textFormat:TextFormat):TextField {
			var textField:TextField = new TextField();
			textField.text = item.text;
			textField.autoSize = TextFieldAutoSize.CENTER;
			textField.defaultTextFormat = textFormat;
			textField.setTextFormat(textFormat);
			return textField;
		}
		
		private function buildTextFieldContainer(item:Item, mouseClick:Function, mouseOver:Function, mouseOut:Function):Sprite {
			var textFieldContainer:Sprite = new Sprite();
			textFieldContainer.cacheAsBitmap = true;
			textFieldContainer.mouseChildren = false;
			textFieldContainer.mouseEnabled = item.enable;
			textFieldContainer.useHandCursor = true;
			textFieldContainer.buttonMode = true;
			textFieldContainer.addChild(item.textField);
			textFieldContainer.addEventListener(MouseEvent.CLICK, function():void {
				if(mouseClick != null) {
					mouseClick(item);
				}
			});
			textFieldContainer.addEventListener(MouseEvent.MOUSE_OVER, function():void {
				if(mouseOver != null) {
					mouseOver(item);
				}
			});
			textFieldContainer.addEventListener(MouseEvent.MOUSE_OUT, function():void {
				if(mouseOut != null) {
					mouseOut(item);
				}
			});
			
			return textFieldContainer;
		}
		
		private function labelMouseClick_Callback(item:Item):void {
			switch(item.action) {
				case Item.ACTION_PAGINATION: {
					showPage(item.index);
					break;
				}
					
				case Item.ACTION_FIRST: {
					showPage(0);
					break;
				}
					
				case Item.ACTION_NEXT: {
					showPage(newPageNo + 1 < totalPagesNo ? newPageNo + 1 : 0);
					break;
				}
					
				case Item.ACTION_PREV: {
					showPage(newPageNo - 1 < 0 ? totalPagesNo - 1 : newPageNo - 1);
					break;
				}
					
				case Item.ACTION_LAST: {
					showPage(totalPagesNo - 1);
					break;
				}
					
				default: {
					break;
				}
			}
		}
		
		private function labelMouseOver_Callback(item:Item):void {
			if(!item.selected) {
				item.textField.defaultTextFormat = textFormatOver;
				item.textField.setTextFormat(textFormatOver);
			}
		}
		
		private function labelMouseOut_Callback(item:Item):void {
			if(!item.selected) {
				item.textField.defaultTextFormat = textFormat;
				item.textField.setTextFormat(textFormat);
			}
		}
	}
}
import flash.text.TextField;

internal class Item extends Object {
	
	public static const ACTION_PAGINATION:String = "ACTION_PAGINATION";
	public static const ACTION_FIRST:String = "ACTION_FIRST";
	public static const ACTION_PREV:String = "ACTION_PREV";
	public static const ACTION_NEXT:String = "ACTION_NEXT";
	public static const ACTION_LAST:String = "ACTION_LAST";
	
	public var action:String = ACTION_PAGINATION;
	public var text:String = "";
	public var index:uint = 0;
	public var enable:Boolean = true;
	public var selected:Boolean = false;
	public var selectable:Boolean = false;
	public var textField:TextField = null;
	
	public function Item() {

	}
}